package org.lc.platform.mybatis.manager.relation;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import org.lc.platform.mybatis.manager.annotation.TreeChildren;
import org.lc.platform.mybatis.manager.annotation.TreeParent;
import org.lc.platform.mybatis.manager.util.ManagerUtil;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

public class TreeRelationBuilder<T> extends BaseRelation<T> {
    private final Class<T> cls;

    private String key;

    private String parent;
    private String parentKey;
    private String childrenKey;

    private boolean exitsTreeLevel = false;

    public TreeRelationBuilder(Class<T> cls, List<T> data) {
        this.cls = cls;
        this.data = data;
        this.setParameters();
    }

    public TreeRelationBuilder(Class<T> cls, List<T> data, List<Map<String, Object>> relationList) {
        this.cls = cls;
        this.data = data;
        this.relationList = relationList;
        this.setParameters();
    }

    public void selectTree() {
        if (this.exitsTreeLevel) {
            this.selectChildren(data);
        }
    }

    private <K> void selectChildren(List<K> values) {
        var keys = getSetList(values, key);
        if (!keys.isEmpty()) {
            var result = getQueryResult(cls, parentKey, keys);
            if (!result.isEmpty()) {
                var middleMap = getGroupByData(result, this.parent);
                values.forEach(d -> {
                    var record = middleMap.get(getReflectValue(d, key));
                    if (record != null) {
                        setReflectValue(d, this.childrenKey, record);
                    }
                });
                this.selectChildren(result);
            }
        }
    }

    private void setParameters() {
        Field[] fields = ReflectUtil.getFields(this.cls);
        TreeChildren children = null;
        TreeParent parent = null;
        for (Field f : fields) {
            var tableId = f.getAnnotation(TableId.class);
            if (tableId != null) {
                this.key = StrUtil.isNotEmpty(tableId.value()) ? tableId.value() : f.getName();
            }
            var c = f.getAnnotation(TreeChildren.class);
            var t = f.getAnnotation(TreeParent.class);
            if (c != null && ManagerUtil.getClsByField(f).equals(this.cls)) {
                children = c;
                this.childrenKey = f.getName();
                TableField field = f.getAnnotation(TableField.class);
                if (field != null && StrUtil.isNotEmpty(field.value())) {
                    this.childrenKey = field.value();
                }
            }
            if (t != null) {
                parent = t;
                this.parent = f.getName();
                this.parentKey = StrUtil.toUnderlineCase(f.getName());
                TableField field = f.getAnnotation(TableField.class);
                if (field != null && StrUtil.isNotEmpty(field.value())) {
                    this.parentKey = field.value();
                }
            }
        }
        if (children != null && parent != null) {
            this.exitsTreeLevel = true;
        }
    }
}
